namespace Todos.Application.TodoLists.Commands;

[AuthConfig(typeof(TodoList), ResourceAccessType.RoleLimit, "Update")]
public class UpdateTodoListCommand : IRequest<ApiResult>, ICommand
{
    public TodoListInDto[] Dtos { get; set; } = [];
}

public class UpdateTodoListCommandHandler(IServiceProvider provider) : IRequestHandler<UpdateTodoListCommand, ApiResult>
{
    public async Task<ApiResult> Handle(UpdateTodoListCommand request, CancellationToken cancellationToken)
    {
        var repository = provider.GetRepository<TodoList>();
        var entities = new List<TodoList>();

        foreach (var dto in request.Dtos)
        {
            var entity = await repository.FindAsync(dto.Id, cancellationToken);
            if (entity == null)
            {
                return new ApiResult(ApiResultType.Error, $"待办列表 ID:{dto.Id} 不存在");
            }

            // 更新实体属性
            dto.MapTo(entity);
            entities.Add(entity);
        }

        await repository.UpdateAsync(entities, cancellationToken);
        return new ApiResult(ApiResultType.Success, $"待办列表 {entities.ExpandAndToString(m => m.Name)} 更新成功");
    }
}

public class UpdateTodoListCommandValidator : AbstractValidator<UpdateTodoListCommand>
{
    public UpdateTodoListCommandValidator(IRepository<TodoList> repository)
    {
        RuleFor(v => v.Dtos).NotEmpty().WithMessage("请至少更新一个待办列表")
        .Must(dtos =>
        {
            var names = dtos.Select(dto => dto.Name).ToList();
            return names.Count == names.Distinct().Count();
        }).WithMessage("批量更新的待办列表中存在重复的名称");

        RuleForEach(m => m.Dtos).ChildRules(dto =>
        {
            dto.RuleFor(m => m.Id).NotEmpty().WithMessage("待办列表ID不能为空");

            dto.RuleFor(m => m.Name).NotEmpty().WithMessage("待办列表名称不能为空")
            .MustAsync(async (model, name, cancellation) =>
            {
                var spec = new TodoListByNameSpec(name);
                var existingList = await repository.GetAsync(spec, cancellation);
                // 如果找不到同名列表，或者找到的是当前正在更新的列表，则验证通过
                return existingList == null || existingList.Id == model.Id;
            }).WithMessage(m => $"待办列表名称{m.Name}已存在");
        });
    }
}